﻿using System.Diagnostics.Contracts;
using System.Linq;

namespace System
{
    public static class TypeExtentions
    {
        /// <summary>Получить тип по его имени из всех загруженных сборок</summary>
        /// <param name="TypeName">Имя типа</param>
        /// <returns>Тип</returns>
        [Diagnostics.DebuggerStepThrough]
        public static Type GetType(string TypeName)
        {
            var lv_TypeArray = AppDomain.CurrentDomain.GetAssemblies().
                SelectMany((a, i) => a.GetTypes()).Where(t => (t.Name == TypeName)).ToArray();
            return lv_TypeArray.Length != 0 ? lv_TypeArray[0] : null;
        }

        [Diagnostics.DebuggerStepThrough]
        public static TAttribute[] GetCustomAttributes<TAttribute>(this Type T)
            where TAttribute : Attribute
        {
            return GetCustomAttributes<TAttribute>(T, false);
        }

        [Diagnostics.DebuggerStepThrough]
        public static TAttribute[] GetCustomAttributes<TAttribute>(this Type T, bool Inherited)
             where TAttribute : Attribute
        {
            return (from a in T.GetCustomAttributes(typeof(TAttribute), Inherited) select a as TAttribute).ToArray();

            //var A = T.GetCustomAttributes(typeof(TAttribute), Inherited).Select(o => o as TAttribute);
            //return new List<TAttribute>(A);
        }

        [Diagnostics.DebuggerStepThrough]
        public static object CreateObject(this Type type)
        {

            //var lv_Info = type.GetConstructor(new Type[] { });
            //if(lv_Info == null)
            //    throw new InvalidOperationException("Не найден конструктор типа " +
            //        type + " без параметров. Для данного типа доступны следующие конструкторы " +
            //        type.GetConstructors().ConvertObjectTo(CInfo =>
            //        {
            //            if(CInfo.Length == 0) return "{}";
            //            var Result = "{" + CInfo[0].ToString();
            //            for(var i = 1; i < CInfo.Length; i++)
            //                Result += "; " + CInfo[i].ToString();
            //            return Result + "}";
            //        }));
            //return lv_Info.Invoke(new object[] { });
            Contract.Requires(type != null);
            return Activator.CreateInstance(type);
        }

        [Diagnostics.DebuggerStepThrough]
        public static T Create<T>() { return (T)CreateObject(typeof(T)); }

        [Diagnostics.DebuggerStepThrough]
        public static object CreateObject(this Type type, params object[] Params)
        {
            //var ParamsTypes = Params == null ? new Type[] { } : Params.ConvertTo(o => o.GetType());
            //var Info = type.GetConstructor(ParamsTypes);
            //if(Info == null)
            //    throw new InvalidOperationException("У типа " + type + 
            //        " на найден конструктор с требуемым набором параметров " + 
            //        ParamsTypes.ConvertObjectTo(T =>
            //    {
            //        if(T.Length == 0) return "{}";
            //        var Result = "{" + T.ToString();
            //        for(var i = 1; i < T.Length; i++)
            //            Result += "; " + T[i].ToString();
            //        return Result + "}";
            //    }) +
            //    " Для данного типа доступны следующие конструкторы " +
            //        type.GetConstructors().ConvertObjectTo(CInfo =>
            //        {
            //            if(CInfo.Length == 0) return "{}";
            //            var Result = "{" + CInfo[0].ToString();
            //            for(var i = 1; i < CInfo.Length; i++)
            //                Result += "; " + CInfo[i].ToString();
            //            return Result + "}";
            //        }));
            //return Info.Invoke(Params);
            Contract.Requires(type != null);
            return Activator.CreateInstance(type, Params);
        }

        [Diagnostics.DebuggerStepThrough]
        public static T Create<T>(params object[] Params) { return (T)CreateObject(typeof(T), Params); }
    }
}
